
#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Common.hpp"
#include "Log.hpp"
#include <cstdlib>
#include <strings.h>
#include "InetAddr.hpp"
using namespace std;
const int gdefaultsockfd = -1;
const int gbackllog = 8;

namespace SocketModule
{
    using namespace LogModule;

    class Socket;
    using SockPtr = shared_ptr<Socket>;

    // 基类:规定创建socket的方法
    // 提供一个/若干个/固定模式的socket的方法
    class Socket
    {
    public:
        virtual ~Socket() = default;
        virtual void SocketOrDie() = 0; // 创建 成功返回套接字否则返回
        virtual bool BindOrDie(int port) = 0;
        virtual bool ListenOrDie() = 0;
        virtual void SetSocketOpt() = 0; // 设置套接字的相关属性
        virtual SockPtr Accepter(InetAddr *client) = 0;
        virtual void Close() = 0;
        virtual int Recv(string *out) = 0;
        virtual int Send(const string &in) = 0;
        virtual int Fd() = 0;

        // 其他方法需要时再加

        void BuildTcpSocket(int port)
        {
            SocketOrDie(); // 创建
            SetSocketOpt();
            BindOrDie(port);
            ListenOrDie();
            //  ListenOrDie();
        }

        // #ifdef WIN
        //    //提供一个创建listensockfd的固定套路
        //    void BuildTcpSocket()
        //    {
        //         SocketOrDie(); //创建
        //         BindOrDie();
        //         ListenOrDie();
        //    }
        //    //提供一个创建udpsockfd的固定套路
        //    void BuildUdpSocket()
        //    {}
        //  #else linux
        //        //提供一个创建listensockfd的固定套路
        //    void BuildTcpSocket()
        //    {
        //         SocketOrDie(); //创建
        //         BindOrDie();
        //         ListenOrDie();
        //    }
        //    //提供一个创建udpsockfd的固定套路
        //    void BuildUdpSocket()
        //    {}

        //  #endif
    };

    // class UdpSocket:public Socket
    // {
    // public:
    //    virtual ~UdpSocket() = default;
    //    virtual int SocketOrDie() = 0;//创建成功返回套接字否则返回
    //    virtual bool BindOrDie() = 0;
    //    virtual bool ListenOrDie() = 0;
    //    virtual void SetSocketOpt() = 0; //设置套接字的相关属性
    //    virtual bool Accepter(int listensockfd) = 0;
    //    virtual void Close(int fd) = 0 ;
    // private:

    // };

    class TcpSocket : public Socket
    {
    public:
        TcpSocket()
            : _sockfd(gdefaultsockfd)
        {
        }

          TcpSocket(int sockfd)
           : _sockfd(sockfd)
        {
        }
        virtual ~TcpSocket() = default;
        // 创建成功返回套接字否则返回
        virtual void SocketOrDie() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(LogLevel::ERROR) << "socket error\n";
                Die(SOCKET_ERR);
            }
            LOG(LogLevel::DEBUG) << "socket create success: " << _sockfd;
        }
             
        virtual void SetSocketOpt() override
        {
            //保证我们的服务器异常断开之后,可以立即重启,不会有bind问题
            int opt = 1;
            int n = ::setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); //参数二是要在哪一层
        }

        virtual bool BindOrDie(int port)
        {
            if (_sockfd == gdefaultsockfd)
                return false;
            // 填充信息
            InetAddr addr(port);
            // 绑定
            int n = ::bind(_sockfd, addr.Netaddr(), addr.NetAddrLen());
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "bind error\n";
                Die(BIND_ERR);
            }
            LOG(LogLevel::DEBUG) << "bind create success: " << _sockfd;
            return true;
        }

        virtual bool ListenOrDie() override
        {
            if (_sockfd == gdefaultsockfd)
                return false;
            int n = ::listen(_sockfd, gbackllog);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "listen error\n";
                Die(LISTEN_ERROR);
            }
            LOG(LogLevel::DEBUG) << "listen create success: " << _sockfd;
            return true;
        }

        // 1.文件描述符 2.谁连的我 -- *client
        virtual SockPtr Accepter(InetAddr *client) override
        {
            if (!client)
                return nullptr; // 合法客户端
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int newsockfd = ::accept(_sockfd, CONV(&peer), &len);
            if (newsockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept error\n";
                return nullptr;
            }
            client->SetAddr(peer, len);
            return make_shared<TcpSocket>(newsockfd);
        }

        virtual void Close() override
        {
            if (_sockfd == gdefaultsockfd)
                return;
            ::close(_sockfd);
        }

        virtual int Recv(string *out) override
        {
            char buffer[1024];
            auto size = ::recv(_sockfd,buffer,sizeof(buffer)-1,0);
            if(size > 0)
            {
                buffer[size] = 0;
                *out = buffer;
            }
             return size;
        }

        virtual int Send(const string &in) override
        {
             auto size = ::send(_sockfd,in.c_str(),in.size(),0);
             return size;
        }
        virtual int Fd() override
        {
            return _sockfd;
        }
        
    private:
        int _sockfd;
    };
}


